﻿using Dysoft.RabbitMQ.Helper;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;

namespace Dysoft.RabbitMQ
{
    /// <summary>
    /// 消费者模块
    /// </summary>
    public partial class MessageQueue
    {
        /// <summary>
        /// 订阅广播消息
        /// </summary>
        /// <typeparam name="T">消息数据类型</typeparam>
        /// <param name="broadcastName">广播名称</param>
        /// <param name="callback">回调方法</param>
        public void Subscribe<T>(string broadcastName, Action<T> callback)
        {
            var queue = Guid.NewGuid().ToString();
            QueueDeclare(queue);
            BindQueue(queue, broadcastName);

            SubscribeData(queue, callback);
        }

        /// <summary>
        /// 订阅队列消息
        /// </summary>
        /// <typeparam name="T">消息数据类型</typeparam>
        /// <param name="queueName">队列名称</param>
        /// <param name="callback">回调方法</param>
        public void SubscribeQueue<T>(string queueName, Action<T> callback)
        {
            QueueDeclare(queueName, false);

            SubscribeData(queueName, callback);
        }

        /// <summary>
        /// 订阅队列消息
        /// </summary>
        /// <typeparam name="T">消息数据类型</typeparam>
        /// <param name="queueName">队列名称</param>
        /// <param name="callback">回调方法</param>
        private void SubscribeData<T>(string queueName, Action<T> callback)
        {
            EventingBasicConsumer consumer = new EventingBasicConsumer(Channel);
            consumer.Received += (model, deliver) =>
            {
                try
                {
                    var data = deliver.Body.FromSerialization<T>();
                    callback?.Invoke(data);
                }
                catch (Exception e)
                {
                    //TODO: 记录日志
                    Console.WriteLine("接收发生异常");
                    Console.WriteLine(e);
                }
                finally
                {
                    if (IsOperationOk)
                    {
                        //手动确认标志，标记为已读，MQ会自动删除该消息
                        Channel.BasicAck(deliver.DeliveryTag, false);
                    }
                    //else
                    //{
                    //    //未能消费此消息，重新放入队列头
                    //    Channel.BasicReject(deliver.DeliveryTag, true);
                    //}
                }
            };

            //指定消费队列
            Channel.BasicConsume(
                queue: queueName,
                autoAck: false,
                consumer: consumer);
        }
    }
}
